#ifndef ABSTRACTENTITY_H
#define ABSTRACTENTITY_H

#include "Vector.h"
#include "AbstractVisitor.h"
#include "Transformation.h"
#include <vector>

class AbstractEntity
{
private:
	bool m_toDelete;

	Position m_relativePosition, m_absolutePosition;
	Vector m_relativeRotation;
	Vector m_relativeVelocity;

	Vector m_rotationVelocity;

	std::string m_name;

protected:
	std::vector<Matrix4> m_matrixes;
	Dimensions m_boundingsize;
	std::vector<AbstractEntity*> m_children;
	AbstractEntity* m_parent;

public:
	AbstractEntity() { m_toDelete = false; m_parent = NULL; m_name = "AbstractEntity"; }
	AbstractEntity( const std::string& name ) { m_toDelete = false; m_parent = NULL; m_name = name; }

	const std::string& getName() { return m_name; }
	void setName( const std::string& x ) { m_name = x; }

	virtual bool isGroup() { return false; }

	virtual void preFrame( float frametime, const std::vector<Matrix4>& matrixes )
	{
		// Position laten bewegen op basis van velocity
		if(getVelocity().x != 0 || getVelocity().y != 0 || getVelocity().z != 0)
		{
			setPosition( getPosition() + getVelocity()*frametime );
		}

		// Rotateren op basis van rotationvelocity
		if(getRotationVelocity().x != 0 || getRotationVelocity().y != 0 || getRotationVelocity().z != 0)
		{
			setRotation( getRotation() + getRotationVelocity() * frametime );
		}

		m_matrixes = matrixes;
	}

	virtual void frame( float frametime ){};
	virtual void postFrame() = 0;

	virtual void accept( AbstractVisitor* v ) = 0;

	// Standaard functies
	const Position& getRelativePosition() { return m_relativePosition; }
	const Vector& getRelativeVelocity() { return m_relativeVelocity; }
	const Vector& getRelativeRotation() { return m_relativeRotation; }

	const Position& getAbsolutePosition() { return m_absolutePosition; }
	void setAbsolutePosition( const Position& x ) { m_absolutePosition = x; }

	void setRelativePosition( const Position& x ) { m_relativePosition = x; }
	void setRelativeVelocity( const Vector& x ) { m_relativeVelocity = x; }
	void setRelativeRotation( const Vector& x ) { m_relativeRotation = x; }

	// Alternative namen
	void setPosition( const Position& x ) { setRelativePosition(x); }
	void setVelocity( const Vector& x ) { setRelativeVelocity(x); }
	void setRotation( const Vector& x ) { setRelativeRotation(x); }

	const Position& getPosition() { return getRelativePosition(); }
	const Vector& getVelocity() { return getRelativeVelocity(); }
	const Vector& getRotation() { return getRelativeRotation(); }

	const Vector& getRotationVelocity() { return m_rotationVelocity; }
	void setRotationVelocity( const Vector& x ) { m_rotationVelocity = x; }

	const Dimensions& getBoundingSize() { return m_boundingsize; }
	void setBoundingSize( const Dimensions& x ) { m_boundingsize = x; }

	bool toDelete() { return m_toDelete; }
	void deleteLater() { m_toDelete = true; }

	virtual void add( AbstractEntity* ent ){}
	virtual void remove( AbstractEntity* ent ){}
	
	virtual const std::vector<AbstractEntity*>& getChildren() { return m_children; }
	std::vector<Matrix4>& getMatrixes() { return m_matrixes; }

	AbstractEntity* getParent() { return m_parent; }
	void setParent( AbstractEntity* x ) { m_parent = x; }

	// Collisie
	virtual bool hasCollision( AbstractEntity* other, bool doublechecked = true ) = 0;
	virtual void checkCollision( AbstractEntity* other ) = 0;
	virtual void collisionResponse( AbstractEntity* other ){};
};

#endif 